package com.chinamsp.dydb.util;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.springframework.beans.BeanUtils;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.chinamsp.baisc.util.ApplicationContextAccessor;
import com.chinamsp.dydb.crud.BaseBiz;
import com.chinamsp.dydb.crud.BaseModel;


/**
 * biz 业务工具类
 * @author shifenghu
 *
 */
@SuppressWarnings("unchecked")
public class BizUtils {

	private static final Map<Class<BaseBiz<?, ?>>,BaseBiz<?, ?>> BIZ_CLASS_CACHED = new HashMap<Class<BaseBiz<?,?>>, BaseBiz<?,?>>(512);
	
	/**
	 * model 层 字段为空的默认值
	 */
	public static final String MODEL_EMPTY_ID = "-1";
	
	/**
	 * 获取biz 实例
	 * @param <T>
	 * @param bizClass
	 * @return
	 */
	public static <T extends BaseBiz<?, ?>> T getBiz(Class<T> bizClass){
		T biz = (T) BIZ_CLASS_CACHED.get(bizClass);
		if(biz == null){
			synchronized (bizClass) {
				biz = (T) BIZ_CLASS_CACHED.get(bizClass);
				if(biz == null){
					biz = ApplicationContextAccessor.getBean(bizClass);
				}
				BIZ_CLASS_CACHED.put((Class<BaseBiz<?, ?>>) bizClass, biz);
			}
		}
		return biz;
	}
	

	
	/**
	 * 功能:把list<model>对象转换成List<long> idList
	 * <p>作者文齐辉 2013-3-28 下午3:40:22
	 * @param list
	 * @return
	 */
	public static List<Integer> toIds(List<? extends BaseModel> list){
		List<Integer> idList = new ArrayList<Integer>();
		for(BaseModel baseModel : list){
			idList.add(baseModel.getId());
		}
		return idList;
	}
	
	
	/**
	 * 获取model list 的id 列表
	 * @param models
	 * @return
	 */
	public static List<Integer> getIds(List<? extends BaseModel> models){
		List<Integer> ids = new ArrayList<Integer>(models.size());
		for(BaseModel m : models){
			ids.add(m.getId());
		}
		return ids;
	}
	
	
	
	/**
	 * 检查model编号是否为空
	 * <p>
	 * 	编号必须存在且大于0，否则将被认为是空
	 * </p>
	 * @param id
	 * @return
	 *
	 * @author shifenghu
	 * @date 2013-9-26
	 */
	public static boolean isEmptyId(BaseModel model){
		return model == null || model.getId() <= 0;
	}
	
	
	/**
	 * 生成一个新的 uuid
	 * @return
	 */
	public static String uuid(){
		return UUID.randomUUID().toString();
	}
	
	/**
	 * 强制使用索引值，当某字段是有索引，而传递的值是empty时，则此函数会将其转换为 {@link #MODEL_EMPTY_ID}
	 * @param value
	 * @return
	 */
	public static String forceUseIndex(String value){
		return StringUtils.isEmpty(value) ? MODEL_EMPTY_ID : value;
	}
	
	/**
	 * 调用方法
	 * @param target
	 * @param method
	 * @param args
	 * @return
	 */
	public static Object invokeMethod(Object target, Method method, Object... args){
		if(target == null || method == null){
			throw new IllegalArgumentException("参数不存在");
		}
		try {
			return method.invoke(target, args);
		}catch (Exception e) {
			throw new IllegalArgumentException("执行" + target.getClass().getName() + "." + method.getName() + "方法失败[" + e.getMessage() + "]", e);
		}
	}
	
	/**
	 * 将 classname 转换成 类
	 * 
	 * @param className
	 * @return
	 */
	public static Class<?> forName(String className){
	    try {
            return ClassUtils.forName(className, ClassUtils.getDefaultClassLoader());
        }catch (Exception e) {
            throw new IllegalArgumentException(e);
        }
	}
	
	/**
	 * 根据构造函数的参数，实例化一个对象
	 * @param <T>
	 * @param clazz
	 * @param params
	 * @return
	 *
	 * @author shifenghu
	 */
	public static <T> T newInstance(Class<T> clazz,Object... params){
		//如果构造函数的参数存在
		if(params != null){
			Class<?>[] cs = new Class<?>[params.length];
			for(int i = 0;i < params.length ;i ++){
				cs[i] = params[i].getClass();
				//如果是代理对象，则获取被代理的接口类
				if(Proxy.isProxyClass(cs[i])){
					cs[i] = cs[i].getInterfaces()[0];
				}
			}
			try {
				return clazz.getConstructor(cs).newInstance(params);
			} catch (Exception e) {
				throw new IllegalArgumentException(e);
			}
		}
		//默认构造方法
		else{
			try {
				return clazz.newInstance();
			}catch (Exception e) {
				throw new IllegalArgumentException(e);
			}
		}
	}
	
	/**
	 * 从列表中强制获取一个元素，如果有多个，只获取第一个
	 * @param list 要获取的列表
	 * @return 获取的元素，如果不存在，则返回 null
	 */
	public static <T> T forceOne(List<T> list){
		if(CollectionUtils.isEmpty(list)){
			return null;
		}
		return list.get(0);
	}
	
	
	/**
	 * 将数据列表转换成另一中bean列表
	 * <p>
	 * 		转换时有如下限制：<br/>
	 * 		1、beanClass必须有默认构造函数<br/>
	 * 		2、属性名称和类型必须一致<br/>
	 * </p>
	 * @param sources 要转换的元数据列表
	 * @param beanClass 转换后的bean class
	 * @return 转换结果
	 */
	public static <T> List<T> convertToBeans(List<?> sources, Class<T> beanClass){
		// 如果source为空，则返回 empty list
		if(CollectionUtils.isEmpty(sources)){
			return new ArrayList<T>(2);
		}
		List<T> list = new ArrayList<T>(sources.size());
		T target;
		// 逐条转换
		for(Object source : sources){
			// 初始化一个 目标对象
			target = newInstance(beanClass);
			// 将源数据转换到目标对象中
			BeanUtils.copyProperties(source, target);
			// 放入结果集中
			list.add(target);
		}
		return list;
	}
}
